#pragma once
#ifndef FILEMAPPING
#define FILEMAPPING
#include <iostream>
#include <string>

using namespace std;

#ifdef _WIN32
#include <Windows.h>

//FileMapping
//文件内存映射类
class FileMapping {
public:

    
    FileMapping() {
        mode = -1;
    }
    //构造函数
    //file: 文件名
    //xmode: 选择读/写模式
    FileMapping(const char* file, int xmode = 0) {
        //调用初始化函数
        init(file, xmode);
    }

    //初始化函数
    //file: 文件名
    //xmode: 选择读/写模式
    void init(const char* file, int xmode = 0);

    //返回读文件长度
    DWORD len_of_reading_file();

    //返回读文件指针
    char* read_content();

    //向文件中写
    //str: 输出内容
    inline void write(string& str) {
        //仅在写模式下可用
        if (mode == 1) {
            cout << "FileMapping is read only now!:" << filename << '\n';
            exit(1);
        }
        else if (mode == -1) {
            cout << "FileMapping should be inited first\n";
            exit(1);
        }
        //写之前，首先检查str输出至文件后，是否超过文件大小
        write_check(str.size());
        //将str输出值文件
        memcpy(map_address + cur, str.c_str(), str.size());

        //更新cur
        cur += str.size();
        //清空str
        str.clear();
    }

    //关闭文件映射
    void close();

private:

    HANDLE file_descriptor = nullptr;   //文件描述符指针
    HANDLE file_mappingobj = nullptr;   //文件映射对象指针
    char* map_address = nullptr;        //文件内容指针
    
    int mode = 0;       //读/写模式
    string filename;    //文件名
    
    DWORD rfilesize = 0;   //读文件大小
    DWORD wfilesize = 256;  //写文件大小，初始为256
    int cur = 0;    //当前文件指针位置

    //当前文件是否映射
    bool is_mapping();

    //映射文件
    //fisze: 映射长度
    void mapping_file(DWORD fsize);

    //关闭文件映射
    void close_mapping();
    //检查写入内容长度
    void write_check(int size);
};
#elif __unix__
#define __unix_linux__
#elif __linux__
#define __unix_linux__
#endif


#ifdef __unix_linux__
#include <sys/stat.h>
#include <sys/mman.h>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
class FileMapping {
public:
    int fd;
    //HANDLE file_descriptor = nullptr;   //文件描述符指针
    //HANDLE file_mappingobj = nullptr;   //文件映射对象指针
    struct stat file_stat;
    char* map_address = nullptr;        //文件内容指针
    
    int mode = 0;       //读/写模式
    std::string filename;    //文件名

    long long filesize;   //读文件大小
    int cur = 0;    //当前文件指针位置
    
    FileMapping() {
        filesize=0;
        mode = -1;
    }
    //构造函数
    //file: 文件名
    //xmode: 选择读/写模式
    FileMapping(const char* file, int xmode = 0) {
        std::cout<<file<<std::endl;
        //调用初始化函数
        init(file, xmode);
    }

    //初始化函数
    //file: 文件名
    //xmode: 选择读/写模式
    void init(const char* file, int xmode = 0);

    //返回读文件长度
    int len_of_reading_file();

    //返回读文件指针
    char* read_content();

    //向文件中写
    //str: 输出内容
    inline void write(string &str) {
        if (mode == 1) {
            cout << "FileMapping is read only now!:" << filename << '\n';
            exit(1);
        }
        else if (mode == -1) {
            cout << "FileMapping should be inited first\n";
            exit(1);
        }
        write_check(str.size());
        memcpy(map_address + cur, str.c_str(), str.size());
        //更新cur
        cur += str.size();
        str.clear();
    }

    //关闭文件映射
    void close();

private:
    //当前文件是否映射
    bool is_mapping();

    //映射文件
    //fisze: 映射长度
    void mapping_file(int fsize);

    //关闭文件映射
    void close_mapping(int fsize);

    //检查写入内容长度
    void write_check(int size);
};
#endif

#endif